'''
装饰器 单例模式
https://www.cnblogs.com/wgbo/archive/2018/11/13/9953446.html
类装饰器本质上和函数装饰器原理、作用相同，都是为其它函数增加额外的功能。但是相比于函数装饰器，类装饰器具有灵活度大、高内聚、封装性等优点。
使用类装饰器可以直接依靠类内部的__call__方法来实现，当使用 @ 形式将类装饰器附加到函数上时，就会调用类装饰器的__call__方法。
而不需要向函数装饰器那样，在装饰器函数中定义嵌套函数，来实现装饰功能。
'''
from functools import wraps
from flask import request, jsonify
from app import lxq
from app.middlerware.Jwt import UserToken

FORBIDDEN = "对不起, 你没有足够的权限"
'''
这里的初始化函数只会调用一次，当第二次装饰的时候，这一步就滤过了
因此，第二次装饰的时候，不会再执行__init__方法，直接返回一个Singleton实例对象，
使得第二次调用__call__方法，发现self.instance有值，那么就直接返回了
'''

class SingleDecorator:

    def __init__(self, cls): # 接收类的实例
        self.cls =cls
        self.instance = None

    def __call__(self, *args, **kwargs):  # 使用__call__()方法来添加装饰器要实现的功能，并在__call__()方法中执行和返回被装饰函数。
        if self.instance is None:
            self.instance = self.cls(*args, **kwargs)
        return self.instance


# 判断用户权限(通过headers中的token字段获取token，经过解析后拿到用户信息)
def permission(role=lxq.config.get("GUEST")):
    def login_required(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                headers = request.headers
                token = headers.get("token")
                if token is None:
                    return jsonify(dict(code=401, msg="用户信息认证失败，请检查"))

                user_info = UserToken.parse_token(token)
                # 把user的信息写入kwargs
                kwargs["user_info"] = user_info
            except Exception as e:
                return jsonify(dict(code=401, msg=str(e)))
            # 判断用户权限是否足够，如果不够则直接返回，不继续
            if int(user_info.get("role", 0)) < role:
                return jsonify(dict(code=400, msg=FORBIDDEN))
            return func(*args, **kwargs)
        return wrapper
    return login_required



